﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace CSequence
{
    public class CWikiSourceControl
    {
        private string m_sSite = "", m_sLogin = "", m_sPassword = "";
            
        public string m_sSCSite = "";
        
        private object m_oSite = null;
        public string sLastError;
        public bool bConnected;
        public List<CSCStatus> listCSCStatus = new List<CSCStatus>();

        public class CSCStatus
        {
            public string sRowTypeId;
            public string sName;
            public string sVersion;
            public string sCheckedOutTo;
            public string sTimeDate;
        }

        public void DisConnect()
        {
            m_oSite = null;
            bConnected = false;
        }

        public string GetStatusCSVList()
        {
            string sInList = "";
            GetSCStatus();
            foreach (CSCStatus oCSCStatus in listCSCStatus)
            {
                sInList += oCSCStatus.sRowTypeId + ",";
            }
            sInList = sInList.Substring(0, sInList.Length - 1);
            return sInList;
        }

        public CSCStatus FindByName(string sName)
        {
            GetSCStatus(); 
            return listCSCStatus.Find(item => item.sName == sName);
        }
        public CSCStatus FindById(string sID)
        {
            GetSCStatus(); 
            return listCSCStatus.Find(item => item.sRowTypeId == sID);
        }

        public bool  Connect()
        {
            sLastError = "";
            try
            {
                bConnected = false;
                if (m_oSite == null)
                {
                    Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                    Type type = assembly.GetType("DotNetWikiBot.Site");
                    m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);
                    bConnected = true;
                }
                bConnected = true;
            }
            catch (Exception e)
            {
                sLastError = e.Message + "-" + e.InnerException;
                bConnected = false;
            }
            return bConnected;
        }

        public bool Connect(string sSite, string sLogin, string sPassword, string sSCSite)
        {
            m_sSite     = sSite;
            m_sLogin    = sLogin;
            m_sPassword = sPassword;
            m_sSCSite = sSCSite;
            Connect();
            return sLastError == "";
        }

        public void Add(string sName, string sId, string sText, string sUser)
        {
            try
            {
                sLastError = "";
                if (Connect())
                {
                    //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                    Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                    Type typePage = assembly.GetType("DotNetWikiBot.Page");

                    //pPage.Load();
                    object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite + "."  + sName);
                    MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                    miLoad.Invoke(pPage, null);

                    FieldInfo fiGetText = pPage.GetType().GetField("text");
                    string sExisting = (string)fiGetText.GetValue(pPage);
                    if (sExisting != "")
                    {
                        sLastError = "Page Text already exists (" + m_sSCSite + "." + sName + ")";
                    }
                    else
                    {
                        string sToSave = "===" + sName + "===\n";
                        sToSave += "<Pre>\n" + sText + "\n</Pre>";

                        string sToTestEx = sExisting.Replace("\r\n", "");
                        sToTestEx = sToTestEx.Replace("\n", "");

                        string sToTestToSave = sToSave.Replace("\r\n", "");
                        sToTestToSave = sToTestToSave.Replace("\n", "");

                        CSCStatus oCSCStatus = listCSCStatus.Find(item => item.sRowTypeId == sId);
                        if (oCSCStatus != null)
                        {
                            sLastError = "Page Id already exists (" + sId + ")";
                        }
                        else
                        {
                            // Now do the update 
                            MethodInfo miSave = typePage.GetMethod("Save", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
                            miSave.Invoke(pPage, new object[] { sToSave });

                            // Update the Id's
                            GetSCStatus();
                            CSCStatus oCSCStatusToAdd = new CSCStatus();
                            oCSCStatusToAdd.sName = sName;
                            oCSCStatusToAdd.sRowTypeId = sId;
                            oCSCStatusToAdd.sCheckedOutTo = sUser;
                            oCSCStatusToAdd.sTimeDate = DateTime.Now.ToString();
                            listCSCStatus.Add(oCSCStatusToAdd);
                            listCSCStatus.Sort((a, b) => Convert.ToInt16(a.sRowTypeId).CompareTo(Convert.ToInt16(b.sRowTypeId)));
                            SaveStatus();
                        }
                    }
                }

            }
            catch (Exception e)
            {
                sLastError = e.Message + "-" + e.InnerException;
            }        
        }

        public void CheckIn(string sName, string sId, string sText, string sUser) 
        {
            try
            {
                if (Connect())
                {
                    sLastError = "";
                    //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                    Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                    Type typePage = assembly.GetType("DotNetWikiBot.Page");

                    //pPage.Load();
                    object pPage = Activator.CreateInstance(typePage, m_oSite,  m_sSCSite + "." + sName);
                    MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                    miLoad.Invoke(pPage, null);

                    FieldInfo fiGetText = pPage.GetType().GetField("text");
                    string sExisting = (string)fiGetText.GetValue(pPage);
                    string sToSave = "===" + sName + "===\n";
                    sToSave += "<Pre>\n" + sText + "\n</Pre>";

                    string sToTestEx = sExisting.Replace("\r\n", "");
                    sToTestEx = sToTestEx.Replace("\n", "");

                    string sToTestToSave = sToSave.Replace("\r\n", "");
                    sToTestToSave = sToTestToSave.Replace("\n", "");

                    if (sToTestEx != sToTestToSave)
                    {
                        MethodInfo miSave = typePage.GetMethod("Save", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
                        miSave.Invoke(pPage, new object[] { sToSave });
                    }
                    else
                    {
                        sLastError = "No changes";
                    }

                    GetSCStatus();
                    CSCStatus oCSCStatus = listCSCStatus.Find(item => item.sRowTypeId == sId);
                    if (oCSCStatus != null)
                    {
                        oCSCStatus.sCheckedOutTo = "-";
                        oCSCStatus.sName = sName;
                        oCSCStatus.sTimeDate = DateTime.Now.ToString();
                        SaveStatus();
                    }
                    else
                    {
                        CSCStatus oCSCStatusToAdd = new CSCStatus();
                        oCSCStatusToAdd.sName = sName;
                        oCSCStatusToAdd.sRowTypeId = sId;
                        oCSCStatusToAdd.sCheckedOutTo = sUser;
                        oCSCStatusToAdd.sTimeDate = DateTime.Now.ToString();
                        listCSCStatus.Add(oCSCStatusToAdd);
                        listCSCStatus.Sort((a, b) => Convert.ToInt16(a.sRowTypeId).CompareTo(Convert.ToInt16(b.sRowTypeId)));
                        SaveStatus();
                    }
                }

            }
            catch (Exception e)
            {
                sLastError = e.Message + "-" + e.InnerException;
            }
        }

        private void SaveStatus()
        {
            string  sStatus = "<Pre>\n";
            foreach ( CSCStatus oSCStatus in listCSCStatus)
            {
                if (oSCStatus.sRowTypeId.Length > 0 )
                    sStatus += oSCStatus.sRowTypeId + "," +  oSCStatus.sName + "," +  oSCStatus.sVersion + "," +  oSCStatus.sCheckedOutTo + "," +  oSCStatus.sTimeDate + "\n";; 
            }
            sStatus += "</Pre>";

            //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
            Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
            Type typePage = assembly.GetType("DotNetWikiBot.Page");

            object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite );
            MethodInfo miLoad = pPage.GetType().GetMethod("Load");
            miLoad.Invoke(pPage, null);

            MethodInfo miSave = typePage.GetMethod("Save", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
            miSave.Invoke(pPage, new object[] { sStatus });

        }

        public string CheckOut(string sId, string sName, string sUser)
        {
            string sExisting = "";
            if (Connect())
            {
                sLastError = "";

                GetSCStatus();
                CSCStatus oCSCStatus = listCSCStatus.Find(item => item.sRowTypeId == sId);
                if (oCSCStatus != null)
                {

                    oCSCStatus.sCheckedOutTo = sUser;
                    oCSCStatus.sTimeDate = DateTime.Now.ToString();
                    SaveStatus();

                    //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                    Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                    Type typePage = assembly.GetType("DotNetWikiBot.Page");

                    object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite + "." + oCSCStatus.sName);
                    MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                    miLoad.Invoke(pPage, null);

                    FieldInfo fiGetText = pPage.GetType().GetField("text");
                    sExisting = (string)fiGetText.GetValue(pPage);
                    SaveStatus();

                }
                else
                {

                    CSCStatus oCSCStatusToAdd = new CSCStatus();
                    oCSCStatusToAdd.sName = sName;
                    oCSCStatusToAdd.sRowTypeId = sId;
                    oCSCStatusToAdd.sCheckedOutTo = sUser;
                    oCSCStatusToAdd.sTimeDate = DateTime.Now.ToString();
                    listCSCStatus.Add(oCSCStatusToAdd);
                    listCSCStatus.Sort((a, b) => Convert.ToInt16(a.sRowTypeId).CompareTo(Convert.ToInt16(b.sRowTypeId)));
                    SaveStatus();
                }

            }
            return sExisting;
        }

        public string GetHistoryAtDate(string sName,DateTime tmTime, ref string sData)
        {
            string sRet = "";
            if (Connect())
            {
                Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                Type typePageList = assembly.GetType("DotNetWikiBot.PageList");

                object pPageList = Activator.CreateInstance(typePageList, m_oSite);
                MethodInfo miFillFromPageHistory = pPageList.GetType().GetMethod("FillFromPageHistoryEx");
                int iPages = 50;
                miFillFromPageHistory.Invoke(pPageList, new object[] { m_sSCSite + "." + sName, iPages, true });

                Type[] paramTypes = { iPages.GetType() };
                object s1 = null, s2 = null;
                string sTimestamp1 = "";               
                PropertyInfo p1 = pPageList.GetType().GetProperty("Item", paramTypes);
                int i = 0; bool bFinished = false; 
                while (!bFinished)
                {
                    try
                    {
                        s2 = s1;
                        s1 = p1.GetValue(pPageList, new Object[] { i++ });
                        if (s1 == null)
                        {
                            bFinished = true;
                            sTimestamp1 = s1.GetType().GetField("timestamp").GetValue(s1).ToString();
                            bFinished = true;
                        }
                        else
                        {
                            DateTime tmNext = ToDate(s1.GetType().GetField("timestamp").GetValue(s1).ToString());
                            if (tmNext <= tmTime)
                            {
                                bFinished = true;
                                if (s1 != null)
                                {
                                    sRet = s1.GetType().GetField("text").GetValue(s1).ToString();
                                    sData = s1.GetType().GetField("lastUser").GetValue(s1).ToString();
                                    sData += "\t" + ToDate(s1.GetType().GetField("timestamp").GetValue(s1).ToString()).ToString("yyyy/MM/dd HH:mm:ss");
                                    sData += "\t" + s1.GetType().GetField("text").GetValue(s1).ToString().Length;                                  
                                }
                            }
                        }
                    }
                    catch( Exception e) 
                    {
                        sLastError = e.Message + "-" + e.InnerException;
                        bFinished = true;
                    }
                }
            }
            return sRet;
        }

        DateTime ToDate(string sDateTime)
        {
            string[] arrDateTime = sDateTime.Split(' ');
            string[] arrDate = arrDateTime[0].Split('/');

            int iYear = Convert.ToInt16(arrDate[2]);
            int iMonth = Convert.ToInt16(arrDate[0]);
            int iDay = Convert.ToInt16(arrDate[1]);

            string[] arrTime = arrDateTime[1].Split(':');

            int iHour = Convert.ToInt16(arrTime[0]);
            int iMin = Convert.ToInt16(arrTime[1]);
            int iSec = Convert.ToInt16(arrTime[2]);

            if (arrDateTime[2] == "PM")
            {
                if (iHour > 12)
                   iHour += 12;
            }

            DateTime tmRet = new DateTime(iYear, iMonth, iDay, iHour, iMin, iSec);
            return tmRet;
        }

        public string GetHistory(string sName)
        {
            string sRet = "";
            if (Connect())
            {
               Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                Type typePageList = assembly.GetType("DotNetWikiBot.PageList");

                object pPageList = Activator.CreateInstance(typePageList, m_oSite);
                MethodInfo miFillFromPageHistory = pPageList.GetType().GetMethod("FillFromPageHistoryEx");
                int iPages = 2;
                miFillFromPageHistory.Invoke(pPageList, new object[] { m_sSCSite + "." + sName, iPages, true });

                Type[] paramTypes = { iPages.GetType() };
                object s1=null, s2=null;
                string slastUser1 = "", slastUser2 = "", sTimestamp1 = "", sTimestamp2 = "";
                int iLen1 = 0, iLen2 = 0;
                PropertyInfo p1 = pPageList.GetType().GetProperty("Item", paramTypes);
                try
                {
                    s1 = p1.GetValue(pPageList, new Object[] { 0 });
                    s2 = p1.GetValue(pPageList, new Object[] { 1 });
                }
                catch
                {
                }

                if (s1 != null)
                    slastUser1 = s1.GetType().GetField("lastUser").GetValue(s1).ToString();
                if (s2 != null) 
                    slastUser2 = s2.GetType().GetField("lastUser").GetValue(s2).ToString();

                if (s1 != null) 
                    sTimestamp1 = s1.GetType().GetField("timestamp").GetValue(s1).ToString();
                if (s2 != null) 
                    sTimestamp2 = s2.GetType().GetField("timestamp").GetValue(s2).ToString();

                if (s1 != null) 
                    iLen1 = s1.GetType().GetField("text").GetValue(s1).ToString().Length;

                if (s2 != null) 
                    iLen2 = s2.GetType().GetField("text").GetValue(s2).ToString().Length;

                sRet= slastUser1 + "\t" + slastUser2 + "\t" + sTimestamp1 + "\t" + sTimestamp2 + "\t" + iLen1.ToString() + "\t" + iLen2.ToString() ;

            }
            return sRet;
        }

        public string GetText(string sName)
        {
            string sExisting = "";
            if (Connect())
            {

                //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                Type typePage = assembly.GetType("DotNetWikiBot.Page");

                object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite + "." + sName);
                MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                miLoad.Invoke(pPage, null);

                FieldInfo fiGetText = pPage.GetType().GetField("text");
                sExisting = (string)fiGetText.GetValue(pPage);
                int iPre = sExisting.IndexOf("<Pre>\n");
                if (iPre > 0)
                    sExisting = sExisting.Substring(iPre + 6);

                sExisting = sExisting.Replace("===" + m_sSCSite + "." + sName + "===\n", "");
                sExisting = sExisting.Replace("===" + sName + "===\n", "");
                sExisting = sExisting.Replace("<Pre>\n", "");
                sExisting = sExisting.Replace("</Pre>", "");
            }
            return sExisting;
        }

        public void Delete(string sId)
        {
            if (Connect())
            {
                GetSCStatus();
                string sStatus = "<Pre>\n";
                foreach (CSCStatus oSCStatus in listCSCStatus)
                {

                    if (oSCStatus.sRowTypeId.Length > 0)
                    {
                        if (Convert.ToInt16(oSCStatus.sRowTypeId) != Convert.ToInt16(sId))
                            sStatus += oSCStatus.sRowTypeId + "," + oSCStatus.sName + "," + oSCStatus.sVersion + "," + oSCStatus.sCheckedOutTo + "," + oSCStatus.sTimeDate + "\n"; ;
                    }
                }
                sStatus += "</Pre>";

                //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                Type typePage = assembly.GetType("DotNetWikiBot.Page");

                object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite );
                MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                miLoad.Invoke(pPage, null);

                MethodInfo miSave = typePage.GetMethod("Save", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
                miSave.Invoke(pPage, new object[] { sStatus });
            }
        }

        public void GetSCStatus()
        {
            if (Connect())
            {
                listCSCStatus.Clear();

                //m_oSite = Activator.CreateInstance(type, m_sSite, m_sLogin, m_sPassword);   
                Assembly assembly = Assembly.LoadFrom("DotNetWikiBot.dll");
                Type typePage = assembly.GetType("DotNetWikiBot.Page");

                //pPage.Load();
                object pPage = Activator.CreateInstance(typePage, m_oSite, m_sSCSite );
                MethodInfo miLoad = pPage.GetType().GetMethod("Load");
                try
                {
                    miLoad.Invoke(pPage, null);

                    FieldInfo fiGetText = pPage.GetType().GetField("text");
                    string sExisting = (string)fiGetText.GetValue(pPage);
                    sExisting = sExisting.Replace("<Pre>\n", "");
                    sExisting = sExisting.Replace("</Pre>", "");

                    string[] sRows = sExisting.Split('\n');
                    foreach (string sRow in sRows)
                    {
                        string[] sProp = sRow.Split(',');
                        if (sProp.Count() == 5)
                        {
                            CSCStatus oCSCStatus = new CSCStatus();
                            oCSCStatus.sRowTypeId = sProp[0];
                            oCSCStatus.sName = sProp[1];
                            oCSCStatus.sVersion = sProp[2];
                            oCSCStatus.sCheckedOutTo = sProp[3];
                            oCSCStatus.sTimeDate = sProp[4];
                            listCSCStatus.Add(oCSCStatus);
                        }

                    }
                }
                catch (Exception e) { sLastError += e.Message; }
            }
        }
    }
}
